function add(x) {
  return x++;
}
function sub(x) {
  return x--;
}
function square(x) {
  return x * x;
}

// console.log(square(sub(add(5)))); // 25

// 1. 手动合并函数
function compose1(add, sub, square) {
  // 这个是一个高阶函数，需要返回一个合并之后的函数
  return (...args) => {
    return square(sub(add(...args)));
  }
}
// 测试
// console.log(compose1(add, sub, square)(5)); // 25

// 2. 支持数组的 compose 函数
function compose2(mids) {
  let len = mids.length;
  return (...args) => {
    let result = null;
    for (let i = 0; i < len; i++) {
      if (i === 0) {
        result = mids[0](...args);
      } else {
        result = mids[i](result);
      }
    }

    return result;
  }
}
// 测试
// console.log(compose2([add, sub, square])(5)); // 25

// 3. 利用 async/await 实现 compose 函数
// 这个 composeAsync 函数还是比较有意思的
function composeAsync(mids) {
  return () => {
    let dispatch = (value) => {
      let fn = mids[value];
      if (!fn) { // 如果执行到了最后一个函数直接返回
        return Promise.resolve();
      }
      let next = () => {
        dispatch(value + 1)
      }
      return Promise.resolve(fn(next));
    }

    // 自动调用第一个函数
    return dispatch(0);
    // 这里是自动调用了第一个函数，这里最好是一步一步往下走，这样可以更好的理解流程
    // 这里还需要注意的是，这个由于是一个实验测试的 compose 函数
    // 所以函数的第一个参数就直接是这个 next 函数了，这个是比较容易产生问题的地方
  }
}

let fn1 = async (next) => {
  console.log("fn1-start");
  await next();
  console.log("fn1-end");
}

let fn2 = async (next) => {
  console.log("fn2-start");
  await next();
  console.log("fn2-end");
}

let fn3 = async (next) => {
  console.log("fn3-start");
  await next();
  console.log("fn3-end");
}

composeAsync([fn1, fn2, fn3])();

